// dllmain.cpp : Implementation of DllMain.

#include "stdafx.h"
#include "resource.h"
#include "XortDebugEngine_i.h"
#include "dllmain.h"
#include "EventBase.h"

CXortDebugEngineModule _AtlModule;

#ifdef _USRDLL
// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	return _AtlModule.DllMain(dwReason, lpReserved); 
}

#else

const DWORD dwPause = 1000; // time to wait for threads to finish up

LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
{
    while (p1 != NULL && *p1 != NULL)
    {
        LPCTSTR p = p2;
        while (p != NULL && *p != NULL)
        {
            if (*p1 == *p)
                return CharNext(p1);
            p = CharNext(p);
        }
        p1 = CharNext(p1);
    }
    return NULL;
}

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, 
    LPTSTR lpCmdLine, int /*nShowCmd*/)
{
    ATLTRACE( "XortDebugEngine -> WinMane ENTER\n" );

    lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
    ATLTRACE( "CMDline: %S", lpCmdLine );

#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
    HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
#else
    HRESULT hRes = CoInitialize(NULL);
#endif
    _ASSERTE(SUCCEEDED(hRes));

    TCHAR szTokens[] = _T("-/");

    int nRet = 0;
    BOOL bRun = TRUE;
    LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
    while (lpszToken != NULL)
    {
        if( lstrcmpi( lpszToken, _T("UnregServer") )==0 )
        {
            _AtlModule.UpdateRegistryFromResource( IDR_XORTDEBUGENGINE, FALSE );
            nRet = _AtlModule.UnregisterServer( TRUE );
            bRun = FALSE;
            break;
        }
        if( lstrcmpi( lpszToken, _T("RegServer") ) == 0 )
        {
            _AtlModule.UpdateRegistryFromResource( IDR_XORTDEBUGENGINE, TRUE );
            nRet = _AtlModule.RegisterServer( TRUE );
            bRun = FALSE;
            break;
        }
        lpszToken = FindOneOf(lpszToken, szTokens);
    }

    if( bRun )
    {
        _AtlModule.StartMonitor();
#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
        hRes = _AtlModule.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
        _ASSERTE(SUCCEEDED(hRes));
        hRes = CoResumeClassObjects();
#else
        hRes = _AtlModule.RegisterClassObjects( CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE );
#endif
        _ASSERTE(SUCCEEDED(hRes));

        MSG msg;
        while( GetMessage( &msg, 0, 0, 0 ) )
        {
            switch( msg.message )
            {
            case WM_BREAKPOINT:
                {
                    //ATLTRACE( "MAIN -> WM_BREAKPOINT\n" );
                    CCodeBreakpointEvent *pEvent = new CCodeBreakpointEvent( (IDebugBoundBreakpoint2 *)msg.wParam );
                    pEvent->Send();
                    break;
                }

            case WM_CANSTOP:
                {
                    //ATLTRACE( "MAIN -> WM_CANSTOP\n" );
                    CComPtr<IXProgram> spXProg = _AtlModule.getXProgramNoAddRef();
                    CComPtr<IDebugDocument2> spDoc;
                    spXProg->GetDocument( &spDoc );
                    CComQIPtr<IDebugDocumentContext2> spDocCtx( spDoc );
                    CCanStopEvent *pEvent = new CCanStopEvent( CANSTOP_STEPIN, spDocCtx, spXProg );
                    pEvent->Send();
                    break;
                }

            case WM_SINGLESTEP:
                {
                    //ATLTRACE( "MAIN -> WM_SINGLESTEP\n" );
                    CStepCompleteEvent *pEvent = new CStepCompleteEvent();
                    pEvent->Send();
                    break;
                }

            case WM_OUTDBG_MESSAGE:
                {
                    //ATLTRACE( "MAIN -> WM_OUTDBG_MESSAGE\n" );
                    COutputStringEvent *pMsgEvent = (COutputStringEvent *)msg.wParam;
                    pMsgEvent->Send();
                    break;
                }

            case WM_EXPR_EVAL:
                {
                    IUnknown *pUnk = (IUnknown *)msg.wParam;
                    CComQIPtr<IXExpression> spXExpr( pUnk );
                    spXExpr->Evaluate( NULL );
                    pUnk->Release();
                    break;
                }

            case WM_PROGRAM_ENDED:
                {
                    ATLTRACE( "MAIN -> WM_PROGRAM_ENDED\n" );
                    CProgramDestroyEvent *pEvent = new CProgramDestroyEvent( 0 );
                    pEvent->Send();

                    CComQIPtr<IDebugEngineLaunch2> spLaunch2( _AtlModule.getEngineNoAddRef() );
                    spLaunch2->TerminateProcess( _AtlModule.getProcessNoAddRef() );
                    break;
                }

            default:
                DispatchMessage( &msg );
                break;
            }
        }

        _AtlModule.RevokeClassObjects();
        Sleep( dwPause ); //wait for any threads to finish
    }

    _AtlModule.Term();
    CoUninitialize();

    ATLTRACE( "XortDebugEngine -> WinMane LEAVE\n" );

    return nRet;
}

#endif
